package com.njtoyo.taxi.admin.service.business.operation_rule.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njtoyo.taxi.admin.cache.PrimaryCachePutter;
import com.njtoyo.taxi.admin.library.common.OperationRecordHelper;
import com.njtoyo.taxi.admin.mapper.master.entity.DriverFlowLog;
import com.njtoyo.taxi.admin.mapper.master.entity.OnlineValuationRule;
import com.njtoyo.taxi.admin.mapper.master.entity.OnlineValuationRuleDetail;
import com.njtoyo.taxi.admin.mapper.master.entity.StartPrice;
import com.njtoyo.taxi.admin.mapper.master.mapper.OnlineValuationRuleDetailMapper;
import com.njtoyo.taxi.admin.mapper.master.mapper.OnlineValuationRuleMapper;
import com.njtoyo.taxi.admin.mapper.master.mapper.StartPriceMapper;
import com.njtoyo.taxi.admin.rest.pojo.dto.rule.online_price_rule.*;
import com.njtoyo.taxi.admin.rest.presenter.business.operation_rule.online_valuation.OnlineValuationPresenter;
import com.njtoyo.taxi.admin.rest.presenter.business.operation_rule.start_price.StartPricePagePresenter;
import com.njtoyo.taxi.admin.rest.wrapper.business.operation_rule.online_valuation.OnlineValuationAddUpdateWrapper;
import com.njtoyo.taxi.admin.rest.wrapper.business.operation_rule.online_valuation.OnlineValuationMockPricingWrapper;
import com.njtoyo.taxi.admin.service.business.StartPriceService;
import com.njtoyo.taxi.admin.service.business.operation_rule.OnlineValuationRuleService;
import com.njtoyo.taxi.admin.utils.DateUtils;
import com.njtoyo.taxi.entity.backend.AdminUser;
import com.taxi.entity.common.RestResult;
import jodd.util.ThreadUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
public class OnlineValuationRuleServiceImpl extends ServiceImpl<OnlineValuationRuleMapper, OnlineValuationRule> implements OnlineValuationRuleService {
    @Autowired
    private OnlineValuationRuleDetailMapper onlineValuationRuleDetailMapper;
    @Autowired
    private PrimaryCachePutter primaryCachePutter;
    @Autowired
    private OperationRecordHelper operationRecordHelper;

    @Override
    public RestResult page(Integer current, Integer size, String driverRegionId, Boolean isActive) {
        Page<OnlineValuationPresenter> page = new Page<>(current, size);
        IPage<OnlineValuationPresenter> pages = baseMapper.getPageList(page, driverRegionId, isActive);
        return RestResult.success(pages);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RestResult add(OnlineValuationAddUpdateWrapper wrapper, AdminUser adminUser) {
        OnlineValuationRule onlineValuationRule = new OnlineValuationRule();
        onlineValuationRule.setDriverRegionId(wrapper.getDriverRegionId());
        onlineValuationRule.setStartTime(DateUtil.date().toString());
        onlineValuationRule.setEndTime("2038-01-01 00:00:00");
        onlineValuationRule.setCreatedBy(adminUser.getName());
        onlineValuationRule.setUpdatedBy(adminUser.getName());
        onlineValuationRule.setCanEditPrice(wrapper.getCanEditPrice());
        onlineValuationRule.setIsActive(wrapper.getIsActive());
        onlineValuationRule.setStartingRule(JSON.toJSONString(Dict.create()
                .set("mileage", wrapper.getStartPriceKM()).set("time", wrapper.getStartPriceMinute())));
        onlineValuationRule.setRefreshRule(JSON.toJSONString(Dict.create()
                .set("mileage", wrapper.getRefreshKM()).set("time", wrapper.getRefreshTime())));
        baseMapper.insert(onlineValuationRule);
        primaryCachePutter.deleteOnlineValuation(wrapper.getDriverRegionId(), null);
        //规则明细  TODO
        //在线计价json配置
        //常规计费规则
        processAddRuleDetails(wrapper.getWorkRuleDetails(), onlineValuationRule.getId(), false);
        //休息日计费规则
        processAddRuleDetails(wrapper.getWeekendRuleDetails(), onlineValuationRule.getId(), true);

        operationRecordHelper.addBusinessLog(String.format("管理员生成线上计价规则，规则id [%d]", onlineValuationRule.getId()));
        return RestResult.success();
    }

    private void processAddRuleDetails(OnlineValuationAddUpdateWrapper.RuleDetail[] ruleDetails, Long ruleId, boolean isWeekend) {
        for (int i = 0; i < ruleDetails.length; i++) {
            OnlineValuationRuleDetail ruleDetailAdd = new OnlineValuationRuleDetail();
            ruleDetailAdd.setRuleId(ruleId);

            OnlineValuationAddUpdateWrapper.RuleDetail ruleDetail = ruleDetails[i];
            OnlinePriceDto onlinePriceDto = new OnlinePriceDto()
                    .setStartingPrice(ruleDetail.getStartPrice())
                    .setExceedStarting(new OnlinePriceDto.ExceedStarting().setMileageUnitPrice(ruleDetail.getMileageUnitPrice()).setTimeUnitPrice(ruleDetail.getTimeUnitPrice()));
            ;
            if (ruleDetail.getFlag().getWaiting()) {
                onlinePriceDto.setWaiting(new OnlinePriceDto.Waiting().setFreeTime(ruleDetail.getWaiting().getFreeTime()).setTimeCost(ruleDetail.getWaiting().getTimeCost()).setLimit(ruleDetail.getWaiting().getLimit()));
            }
            if (ruleDetail.getFlag().getEmptyBackFee()) {
                onlinePriceDto.setEmptyBackFee(new OnlinePriceDto.EmptyBackFee().setBaseMileage(ruleDetail.getEmptyBackFee().getBaseMileage()).setRatio(new BigDecimal(ruleDetail.getEmptyBackFee().getRatio())
                        .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP).toString()));
            }
            if (ruleDetail.getFlag().getBadWeather()) {
                Date startDate = null;
                Date endDate = null;
                if (ruleDetail.getBadWeather().getStartTime().contains("T")) {
                    startDate = DateUtil.offsetHour(DateUtil.parseUTC(ruleDetail.getBadWeather().getStartTime()), 8);
                } else {
                    startDate = DateUtil.parse(ruleDetail.getBadWeather().getStartTime());
                }
                if (ruleDetail.getBadWeather().getEndTime().contains("T")) {
                    endDate = DateUtil.offsetHour(DateUtil.parseUTC(ruleDetail.getBadWeather().getEndTime()), 8);
                } else {
                    endDate = DateUtil.parse(ruleDetail.getBadWeather().getEndTime());
                }
                onlinePriceDto.setBadWeather(new OnlinePriceDto.BadWeather().setPrice(ruleDetail.getBadWeather().getPrice())
                        .setStartTime(startDate.toString()).setEndTime(endDate.toString()));
            }
            if (ruleDetail.getFlag().getHoliday()) {
                onlinePriceDto.setHoliday(new OnlinePriceDto.Holiday().setPrice(ruleDetail.getHoliday().getPrice()).setDays(ruleDetail.getHoliday().getDays()));
            }
            ruleDetailAdd.setPriceRule(JSON.toJSONString(onlinePriceDto));


            OnlinePriceMarkUpDto markUpDto = new OnlinePriceMarkUpDto();
            if (StrUtil.isBlank(ruleDetail.getPriceMarkup().getStep())) {
                markUpDto.setRange(new String[]{}).setStep("");
            } else {
                markUpDto.setStep(ruleDetail.getPriceMarkup().getStep())
                        .setRange(new String[]{ruleDetail.getPriceMarkup().getRangeStart(), ruleDetail.getPriceMarkup().getRangeEnd()});
            }
            ruleDetailAdd.setPriceMarkupRule(JSON.toJSONString(markUpDto));


            if (ruleDetail.getFlag().getDriverCommission()) {
                Dict driverCommissionOption = setOption(ruleDetail.getDriverCommission().getFlag());
                OnlinePriceFlagDto driverCommission = new OnlinePriceFlagDto()
                        .setRatio(new BigDecimal(ruleDetail.getDriverCommission().getRatio()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP).toString())
                        .setOption(driverCommissionOption)
                        .setMin(ruleDetail.getDriverCommission().getMin())
                        .setMax(ruleDetail.getDriverCommission().getMax());
                ruleDetailAdd.setDriverCommissionRule(JSON.toJSONString(driverCommission));
            }
            if (ruleDetail.getFlag().getInfoFee()) {
                Dict infoFeeOption = setOption(ruleDetail.getInfoFee().getFlag());
                OnlinePriceFlagDto infoFee = new OnlinePriceFlagDto()
                        .setRatio(new BigDecimal(ruleDetail.getInfoFee().getRatio()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP).toString())
                        .setOption(infoFeeOption)
                        .setMin(ruleDetail.getInfoFee().getMin())
                        .setMax(ruleDetail.getInfoFee().getMax());
                ruleDetailAdd.setInfoFeeRule(JSON.toJSONString(infoFee));


            }
            List<OnlinePriceTimeRangeDto> timeRanges = new ArrayList<>();
            for (int j = 0; j < ruleDetail.getTimeRanges().length; j++) {
                Date startDate = null;
                Date endDate = null;
                if (ruleDetail.getTimeRanges()[j].getStartTime().contains("T")) {
                    startDate = DateUtil.offsetHour(DateUtil.parseUTC(ruleDetail.getTimeRanges()[j].getStartTime()), 8);
                } else {
                    startDate = DateUtil.parse(ruleDetail.getTimeRanges()[j].getStartTime());
                }
                if (ruleDetail.getTimeRanges()[j].getEndTime().contains("T")) {
                    endDate = DateUtil.offsetHour(DateUtil.parseUTC(ruleDetail.getTimeRanges()[j].getEndTime()), 8);
                } else {
                    endDate = DateUtil.parse(ruleDetail.getTimeRanges()[j].getEndTime());
                }
                OnlinePriceTimeRangeDto timeRangeDto = new OnlinePriceTimeRangeDto()
                        .setStartTime(LocalTime.parse(DateUtil.format(startDate, "HH:mm")).toString())
                        .setEndTime(LocalTime.parse(DateUtil.format(endDate, "HH:mm")).toString());
                timeRanges.add(timeRangeDto);

            }
            System.out.println("timeRanges: " + JSONUtil.toJsonPrettyStr(timeRanges));
            ruleDetailAdd.setPeriod(JSON.toJSONString(timeRanges));
            ruleDetailAdd.setTitle(ruleDetail.getTitle());
            ruleDetailAdd.setIsWeekend(isWeekend);
            onlineValuationRuleDetailMapper.insert(ruleDetailAdd);
            primaryCachePutter.deleteOnlineValuation(null, ruleDetailAdd.getId());
        }
    }

    @Override
    public RestResult getDetailById(String id) {
        OnlineValuationRule onlineValuationRule = baseMapper.selectById(id);
        OnlineValuationAddUpdateWrapper resultVo = new OnlineValuationAddUpdateWrapper();
        resultVo.setId(onlineValuationRule.getId());
        resultVo.setDriverRegionId(onlineValuationRule.getDriverRegionId());
        resultVo.setIsActive(onlineValuationRule.getIsActive());
        resultVo.setCanEditPrice(onlineValuationRule.getCanEditPrice());
        resultVo.setStartPriceKM(JSON.parseObject(onlineValuationRule.getStartingRule()).getString("mileage"));
        resultVo.setStartPriceMinute(JSON.parseObject(onlineValuationRule.getStartingRule()).getString("time"));
        resultVo.setRefreshKM(JSON.parseObject(onlineValuationRule.getRefreshRule()).getString("mileage"));
        resultVo.setRefreshTime(JSON.parseObject(onlineValuationRule.getRefreshRule()).getString("time"));
        List<OnlineValuationRuleDetail> details = onlineValuationRuleDetailMapper.selectList(Wrappers.<OnlineValuationRuleDetail>lambdaQuery()
                .eq(OnlineValuationRuleDetail::getRuleId, id));
        if (CollUtil.isEmpty(details)) {
            return RestResult.failed("规则明细不存在");
        }
        List<OnlineValuationRuleDetail> weekendDetails = details.stream().filter(detail -> BooleanUtil.isTrue(detail.getIsWeekend())).collect(Collectors.toList());
        List<OnlineValuationRuleDetail> workDetails = details.stream().filter(detail -> BooleanUtil.isFalse(detail.getIsWeekend())).collect(Collectors.toList());
        assembleDetails(weekendDetails, resultVo, true);
        assembleDetails(workDetails, resultVo, false);
        return RestResult.success(resultVo);
    }

    private void assembleDetails(List<OnlineValuationRuleDetail> details, OnlineValuationAddUpdateWrapper resultVo, Boolean isWeekend) {
        List<OnlineValuationAddUpdateWrapper.RuleDetail> ruleDetails = new ArrayList<>();
        for (OnlineValuationRuleDetail detail : details) {
            OnlineValuationAddUpdateWrapper.RuleDetail ruleDetail = new OnlineValuationAddUpdateWrapper.RuleDetail();
            //页面checkbox选中状态
            OnlineValuationAddUpdateWrapper.RuleDetail.Flag checkedFlag = new OnlineValuationAddUpdateWrapper.RuleDetail.Flag();
            ruleDetail.setTitle(detail.getTitle());
            ruleDetail.setDetailId(detail.getId());
            List<OnlinePriceTimeRangeDto> timeList = JSON.parseArray(detail.getPeriod(), OnlinePriceTimeRangeDto.class);
            OnlineValuationAddUpdateWrapper.RuleDetail.TimeRange[] timeRanges = new OnlineValuationAddUpdateWrapper.RuleDetail.TimeRange[timeList.size()];
            for (int i = 0; i < timeList.size(); i++) {
                OnlineValuationAddUpdateWrapper.RuleDetail.TimeRange timeRange = new OnlineValuationAddUpdateWrapper.RuleDetail.TimeRange();
                Date startTime = DateUtil.parseDateTime(StrUtil.format("{} {}:00", "1970-01-01", timeList.get(i).getStartTime()));
                Date endTime = DateUtil.parseDateTime(StrUtil.format("{} {}:59", "1970-01-01", timeList.get(i).getEndTime()));
                timeRange.setIndex(i);
                timeRange.setStartTime(startTime.toString());
                timeRange.setEndTime(endTime.toString());
                timeRanges[i] = timeRange;
            }
            ruleDetail.setTimeRanges(timeRanges);
            ruleDetail.setStartPrice(JSON.parseObject(detail.getPriceRule()).getString("startingPrice"));
            ruleDetail.setMileageUnitPrice(JSON.parseObject(detail.getPriceRule()).getJSONObject("exceedStarting").getString("mileageUnitPrice"));
            ruleDetail.setTimeUnitPrice(JSON.parseObject(detail.getPriceRule()).getJSONObject("exceedStarting").getString("timeUnitPrice"));
            ruleDetail.setFlag(new OnlineValuationAddUpdateWrapper.RuleDetail.Flag());
            if (detail.getPriceRule().contains("waiting")) {
                JSONObject waitingObject = JSON.parseObject(detail.getPriceRule()).getJSONObject("waiting");
                ruleDetail.setWaiting(new OnlineValuationAddUpdateWrapper.RuleDetail.Waiting()
                        .setFreeTime(waitingObject.getString("freeTime"))
                        .setTimeCost(waitingObject.getString("timeCost"))
                        .setLimit(waitingObject.getString("limit")));
                ruleDetail.getFlag().setWaiting(true);
            } else {
                ruleDetail.setWaiting(new OnlineValuationAddUpdateWrapper.RuleDetail.Waiting());
                ruleDetail.getFlag().setWaiting(false);
            }
            //加价
            JSONObject priceMarkupObject = JSON.parseObject(detail.getPriceMarkupRule());
            if (priceMarkupObject != null && StrUtil.isNotBlank(priceMarkupObject.getString("step"))) {
                JSONArray range = priceMarkupObject.getJSONArray("range");
                ruleDetail.setPriceMarkup(new OnlineValuationAddUpdateWrapper.RuleDetail.PriceMarkUp()
                        .setRangeStart(range.getString(0))
                        .setRangeEnd(range.getString(1))
                        .setStep(priceMarkupObject.getString("step")));
                ruleDetail.getFlag().setPriceMarkup(true);
            } else {
                ruleDetail.setPriceMarkup(new OnlineValuationAddUpdateWrapper.RuleDetail.PriceMarkUp());
                ruleDetail.getFlag().setPriceMarkup(false);
            }
            //空驶费
            JSONObject emptyBackFeeObject = JSON.parseObject(detail.getPriceRule()).getJSONObject("emptyBackFee");
            if (emptyBackFeeObject != null && StrUtil.isNotBlank(emptyBackFeeObject.getString("ratio"))) {
                ruleDetail.setEmptyBackFee(new OnlineValuationAddUpdateWrapper.RuleDetail.EmptyBackFee()
                        .setRatio(Convert.toBigDecimal(emptyBackFeeObject.getString("ratio")).multiply(Convert.toBigDecimal("100")).toString())
                        .setBaseMileage(emptyBackFeeObject.getString("baseMileage")));
                ruleDetail.getFlag().setEmptyBackFee(true);
            } else {
                ruleDetail.setEmptyBackFee(new OnlineValuationAddUpdateWrapper.RuleDetail.EmptyBackFee());
                ruleDetail.getFlag().setEmptyBackFee(false);
            }
            //恶劣天气费
            JSONObject badWeatherObject = JSON.parseObject(detail.getPriceRule()).getJSONObject("badWeather");
            if (badWeatherObject != null && StrUtil.isNotBlank(badWeatherObject.getString("price"))) {
                ruleDetail.setBadWeather(new OnlineValuationAddUpdateWrapper.RuleDetail.BadWeather()
                        .setPrice(badWeatherObject.getString("price"))
                        .setStartTime(badWeatherObject.getString("startTime"))
                        .setEndTime(badWeatherObject.getString("endTime"))
                );
                ruleDetail.getFlag().setBadWeather(true);
            } else {
                ruleDetail.setBadWeather(new OnlineValuationAddUpdateWrapper.RuleDetail.BadWeather());
                ruleDetail.getFlag().setBadWeather(false);
            }
            //节假日费
            JSONObject holidayObject = JSON.parseObject(detail.getPriceRule()).getJSONObject("holiday");
            if (holidayObject != null && StrUtil.isNotBlank(holidayObject.getString("price"))) {
                OnlineValuationAddUpdateWrapper.RuleDetail.Holiday holiday = new OnlineValuationAddUpdateWrapper.RuleDetail.Holiday();
                holiday.setPrice(holidayObject.getString("price"));
                JSONArray daysArray = holidayObject.getJSONArray("days");
                if (CollUtil.isNotEmpty(daysArray)) {
                    OnlineValuationAddUpdateWrapper.RuleDetail.Days[] days = new OnlineValuationAddUpdateWrapper.RuleDetail.Days[daysArray.size()];
                    for (int i = 0; i < daysArray.size(); i++) {
                        OnlineValuationAddUpdateWrapper.RuleDetail.Days day = new OnlineValuationAddUpdateWrapper.RuleDetail.Days();
                        day.setStartTime(daysArray.getJSONObject(i).getString("startTime"));
                        day.setEndTime(daysArray.getJSONObject(i).getString("endTime"));
                        day.setIndex(i);
                        days[i] = day;
                    }
                    ruleDetail.setHoliday(holiday.setDays(days));
                }
                ruleDetail.getFlag().setHoliday(true);
            } else {
                ruleDetail.setHoliday(new OnlineValuationAddUpdateWrapper.RuleDetail.Holiday()
                        .setDays(new OnlineValuationAddUpdateWrapper.RuleDetail.Days[]{
                                new OnlineValuationAddUpdateWrapper.RuleDetail.Days().setStartTime(null).setEndTime(null).setIndex(0)
                        }));
                ruleDetail.getFlag().setHoliday(false);
            }
            //司机抽成
            JSONObject driverCommissionObject = JSON.parseObject(detail.getDriverCommissionRule());
            if (driverCommissionObject != null && StrUtil.isNotBlank(driverCommissionObject.getString("ratio"))) {
                JSONObject jsonObject = driverCommissionObject.getJSONObject("option");
                JSONArray checkedArray = new JSONArray();
                for (String key : jsonObject.keySet()) {
                    Boolean checked = jsonObject.getBoolean(key);
                    if (checked) {
                        checkedArray.add(key);
                    }
                }
                ruleDetail.setDriverCommission(new OnlinePriceOptionDto()
                        .setMin(driverCommissionObject.getBigDecimal("min"))
                        .setMax(driverCommissionObject.getBigDecimal("max"))
                        .setRatio(Convert.toBigDecimal(driverCommissionObject.getString("ratio")).multiply(Convert.toBigDecimal("100")).toString())
                        .setFlag(checkedArray.toArray(new String[checkedArray.size()])));
                ruleDetail.getFlag().setDriverCommission(true);
            } else {
                ruleDetail.setDriverCommission(new OnlinePriceOptionDto()
                        .setFlag(new String[]{"startingFee", "exceedMileageFee", "exceedTimeFee"}));
                ruleDetail.getFlag().setDriverCommission(false);
            }
            //信息服务费
            JSONObject infoFeeObject = JSON.parseObject(detail.getInfoFeeRule());
            if (infoFeeObject != null && StrUtil.isNotBlank(infoFeeObject.getString("ratio"))) {
                JSONObject jsonObject = infoFeeObject.getJSONObject("option");
                JSONArray checkedArray = new JSONArray();
                for (String key : jsonObject.keySet()) {
                    Boolean checked = jsonObject.getBoolean(key);
                    if (checked) {
                        checkedArray.add(key);
                    }
                }
                ruleDetail.setInfoFee(new OnlinePriceOptionDto()
                        .setMin(infoFeeObject.getBigDecimal("min"))
                        .setMax(infoFeeObject.getBigDecimal("max"))
                        .setRatio(Convert.toBigDecimal(infoFeeObject.getString("ratio")).multiply(Convert.toBigDecimal("100")).toString())
                        .setFlag(checkedArray.toArray(new String[checkedArray.size()])));
                ruleDetail.getFlag().setInfoFee(true);
            } else {
                ruleDetail.setInfoFee(new OnlinePriceOptionDto()
                        .setFlag(new String[]{"startingFee", "exceedMileageFee", "exceedTimeFee"}));
                ruleDetail.getFlag().setInfoFee(false);
            }
            ruleDetails.add(ruleDetail);
        }
        if (isWeekend) {
            resultVo.setWeekendRuleDetails(Arrays.copyOf(ruleDetails.toArray(), ruleDetails.size(), OnlineValuationAddUpdateWrapper.RuleDetail[].class));
        } else {
            resultVo.setWorkRuleDetails(Arrays.copyOf(ruleDetails.toArray(), ruleDetails.size(), OnlineValuationAddUpdateWrapper.RuleDetail[].class));
        }
    }

    @Override
    public RestResult update(OnlineValuationAddUpdateWrapper wrapper, AdminUser adminUser) {
        OnlineValuationRule onlineValuationRule = new OnlineValuationRule();
        onlineValuationRule.setId(wrapper.getId());
        onlineValuationRule.setDriverRegionId(wrapper.getDriverRegionId());
        onlineValuationRule.setUpdatedBy(adminUser.getName());
        onlineValuationRule.setUpdatedAt(new Date());
        onlineValuationRule.setIsActive(wrapper.getIsActive());
        onlineValuationRule.setCanEditPrice(wrapper.getCanEditPrice());
        onlineValuationRule.setStartingRule(JSON.toJSONString(Dict.create()
                .set("mileage", wrapper.getStartPriceKM()).set("time", wrapper.getStartPriceMinute())));
        onlineValuationRule.setRefreshRule(JSON.toJSONString(Dict.create()
                .set("mileage", wrapper.getRefreshKM()).set("time", wrapper.getRefreshTime())));
        baseMapper.updateById(onlineValuationRule);
        primaryCachePutter.deleteOnlineValuation(wrapper.getDriverRegionId(), null);


        List<OnlineValuationRuleDetail> existingDetails = onlineValuationRuleDetailMapper.selectList(
                Wrappers.<OnlineValuationRuleDetail>lambdaQuery()
                        .eq(OnlineValuationRuleDetail::getRuleId, wrapper.getId()));


        Set<Long> incomingDetailIds = Stream.concat(Arrays.stream(wrapper.getWeekendRuleDetails()), Arrays.stream(wrapper.getWorkRuleDetails()))
                .map(OnlineValuationAddUpdateWrapper.RuleDetail::getDetailId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        existingDetails.stream()
                .filter(detail -> !incomingDetailIds.contains(detail.getId()))
                .forEach(detail -> {
                    onlineValuationRuleDetailMapper.deleteById(detail.getId());
                    primaryCachePutter.deleteOnlineValuation(null, detail.getId());
                });


//        规则明细  TODO
//        在线计价json配置

        processUpdateRuleDetails(wrapper.getWorkRuleDetails(), wrapper.getId(), false);
        processUpdateRuleDetails(wrapper.getWeekendRuleDetails(), wrapper.getId(), true);
        operationRecordHelper.addBusinessLog(String.format("管理员修改线上计价规则，规则id [%d]", onlineValuationRule.getId()));
        return RestResult.success();
    }


    private void processUpdateRuleDetails(OnlineValuationAddUpdateWrapper.RuleDetail[] ruleDetails, Long ruleId, boolean isWeekend) {
        for (int i = 0; i < ruleDetails.length; i++) {
            OnlineValuationAddUpdateWrapper.RuleDetail ruleDetail = ruleDetails[i];

            OnlineValuationRuleDetail ruleDetailUpdate = new OnlineValuationRuleDetail();
            ruleDetailUpdate.setRuleId(ruleId);
            ruleDetailUpdate.setIsWeekend(isWeekend);


            OnlinePriceDto onlinePriceDto = new OnlinePriceDto()
                    .setStartingPrice(ruleDetail.getStartPrice())
                    .setExceedStarting(new OnlinePriceDto.ExceedStarting().setMileageUnitPrice(ruleDetail.getMileageUnitPrice()).setTimeUnitPrice(ruleDetail.getTimeUnitPrice()));
            ;
            if (ruleDetail.getFlag().getWaiting()) {
                onlinePriceDto.setWaiting(new OnlinePriceDto.Waiting().setFreeTime(ruleDetail.getWaiting().getFreeTime()).setTimeCost(ruleDetail.getWaiting().getTimeCost()).setLimit(ruleDetail.getWaiting().getLimit()));
            }
            if (ruleDetail.getFlag().getEmptyBackFee()) {
                onlinePriceDto.setEmptyBackFee(new OnlinePriceDto.EmptyBackFee().setBaseMileage(ruleDetail.getEmptyBackFee().getBaseMileage()).setRatio(new BigDecimal(ruleDetail.getEmptyBackFee().getRatio())
                        .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP).toString()));
            }
            if (ruleDetail.getFlag().getBadWeather()) {
                Date startDate = null;
                Date endDate = null;
                if (ruleDetail.getBadWeather().getStartTime().contains("T")) {
                    startDate = DateUtil.offsetHour(DateUtil.parseUTC(ruleDetail.getBadWeather().getStartTime()), 8);
                } else {
                    startDate = DateUtil.parse(ruleDetail.getBadWeather().getStartTime());
                }
                if (ruleDetail.getBadWeather().getEndTime().contains("T")) {
                    endDate = DateUtil.offsetHour(DateUtil.parseUTC(ruleDetail.getBadWeather().getEndTime()), 8);
                } else {
                    endDate = DateUtil.parse(ruleDetail.getBadWeather().getEndTime());
                }
                onlinePriceDto.setBadWeather(new OnlinePriceDto.BadWeather().setPrice(ruleDetail.getBadWeather().getPrice())
                        .setStartTime(startDate.toString()).setEndTime(endDate.toString()));
            }
            if (ruleDetail.getFlag().getHoliday()) {
                onlinePriceDto.setHoliday(new OnlinePriceDto.Holiday().setPrice(ruleDetail.getHoliday().getPrice()).setDays(ruleDetail.getHoliday().getDays()));
            }
            ruleDetailUpdate.setPriceRule(JSON.toJSONString(onlinePriceDto));


            OnlinePriceMarkUpDto markUpDto = new OnlinePriceMarkUpDto();
            if (!ruleDetail.getFlag().getPriceMarkup()) {
                markUpDto.setRange(new String[]{}).setStep("");
            } else {
                markUpDto.setStep(ruleDetail.getPriceMarkup().getStep())
                        .setRange(new String[]{ruleDetail.getPriceMarkup().getRangeStart(), ruleDetail.getPriceMarkup().getRangeEnd()});
            }
            ruleDetailUpdate.setPriceMarkupRule(JSON.toJSONString(markUpDto));


            if (ruleDetail.getFlag().getDriverCommission()) {
                Dict driverCommissionOption = setOption(ruleDetail.getDriverCommission().getFlag());
                OnlinePriceFlagDto driverCommission = new OnlinePriceFlagDto()
                        .setRatio(new BigDecimal(ruleDetail.getDriverCommission().getRatio()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP).toString())
                        .setOption(driverCommissionOption)
                        .setMin(ruleDetail.getDriverCommission().getMin())
                        .setMax(ruleDetail.getDriverCommission().getMax());
                ruleDetailUpdate.setDriverCommissionRule(JSON.toJSONString(driverCommission));
            } else {
                UpdateWrapper<OnlineValuationRuleDetail> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq("id", ruleDetail.getDetailId()).set("driver_commission_rule", null);
                onlineValuationRuleDetailMapper.update(null, updateWrapper);
            }
            if (ruleDetail.getFlag().getInfoFee()) {
                Dict infoFeeOption = setOption(ruleDetail.getInfoFee().getFlag());
                OnlinePriceFlagDto infoFee = new OnlinePriceFlagDto()
                        .setRatio(new BigDecimal(ruleDetail.getInfoFee().getRatio()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP).toString())
                        .setOption(infoFeeOption)
                        .setMin(ruleDetail.getInfoFee().getMin())
                        .setMax(ruleDetail.getInfoFee().getMax());
                ruleDetailUpdate.setInfoFeeRule(JSON.toJSONString(infoFee));
            } else {
                UpdateWrapper<OnlineValuationRuleDetail> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq("id", ruleDetail.getDetailId()).set("info_fee_rule", null);
                onlineValuationRuleDetailMapper.update(null, updateWrapper);
            }
            List<OnlinePriceTimeRangeDto> timeRanges = new ArrayList<>();
            for (int j = 0; j < ruleDetail.getTimeRanges().length; j++) {
                Date startDate = null;
                Date endDate = null;
                if (ruleDetail.getTimeRanges()[j].getStartTime().contains("T")) {
                    startDate = DateUtil.offsetHour(DateUtil.parseUTC(ruleDetail.getTimeRanges()[j].getStartTime()), 8);
                } else {
                    startDate = DateUtil.parse(ruleDetail.getTimeRanges()[j].getStartTime());
                }
                if (ruleDetail.getTimeRanges()[j].getEndTime().contains("T")) {
                    endDate = DateUtil.offsetHour(DateUtil.parseUTC(ruleDetail.getTimeRanges()[j].getEndTime()), 8);
                } else {
                    endDate = DateUtil.parse(ruleDetail.getTimeRanges()[j].getEndTime());
                }
                OnlinePriceTimeRangeDto timeRangeDto = new OnlinePriceTimeRangeDto()
                        .setStartTime(LocalTime.parse(DateUtil.format(startDate, "HH:mm")).toString())
                        .setEndTime(LocalTime.parse(DateUtil.format(endDate, "HH:mm")).toString());
                timeRanges.add(timeRangeDto);
            }
            ruleDetailUpdate.setPeriod(JSON.toJSONString(timeRanges));
            ruleDetailUpdate.setTitle(ruleDetail.getTitle());
            if (ruleDetail.getDetailId() == null) {
                onlineValuationRuleDetailMapper.insert(ruleDetailUpdate);
            } else {
                ruleDetailUpdate.setId(ruleDetail.getDetailId());
                ruleDetailUpdate.setIsWeekend(isWeekend);
                onlineValuationRuleDetailMapper.updateById(ruleDetailUpdate);
            }
            primaryCachePutter.deleteOnlineValuation(null, ruleDetailUpdate.getRuleId());
        }
    }


    @Override
    public RestResult switchIsActive(OnlineValuationRule rule) {
        baseMapper.updateById(rule);

        OnlineValuationRule onlineValuationRule = baseMapper.selectById(rule.getId());
        if (ObjectUtil.isNotNull(onlineValuationRule)) {
            //清除缓存
            primaryCachePutter.deleteOnlineValuation(onlineValuationRule.getDriverRegionId(), null);
        }
        List<OnlineValuationRuleDetail> onlineValuationRuleDetails = onlineValuationRuleDetailMapper.selectList(Wrappers.<OnlineValuationRuleDetail>lambdaQuery().eq(OnlineValuationRuleDetail::getRuleId, rule.getId()));
        for (OnlineValuationRuleDetail onlineValuationRuleDetail : onlineValuationRuleDetails) {
            primaryCachePutter.deleteOnlineValuation(null, onlineValuationRuleDetail.getId());
        }
        operationRecordHelper.addBusinessLog(String.format("管理员[%s]线上计价规则，规则id [%d]", rule.getIsActive() ? "开启" : "关闭", onlineValuationRule.getId()));
        return RestResult.success();
    }

    @Override
    public List<OnlineValuationRule> selectByDriverRegionIdOpen(Long driverRegionId, Long ruleId) {
        LambdaQueryWrapper<OnlineValuationRule> queryWrapper = new LambdaQueryWrapper<>();
        if (ruleId != null) {
            queryWrapper.not(i -> i.eq(OnlineValuationRule::getId, ruleId));
        }
        queryWrapper.eq(OnlineValuationRule::getDriverRegionId, driverRegionId)
                .eq(OnlineValuationRule::getIsActive, true);
        List<OnlineValuationRule> onlineValuationRules = baseMapper.selectList(queryWrapper);
        return onlineValuationRules;
    }

    @Override
    public OnlineValuationRule selectOneById(Long id) {
        return baseMapper.selectById(id);
    }

    @Override
    public RestResult checkDriverRegionIsActive(String driverRegionId) {
        OnlineValuationRule isActive = baseMapper.selectOne(Wrappers.<OnlineValuationRule>lambdaQuery()
                .eq(OnlineValuationRule::getDriverRegionId, driverRegionId)
                .eq(OnlineValuationRule::getIsActive, true));
        return RestResult.success(isActive);
    }

    @Override
    public RestResult switchCanEditPrice(OnlineValuationRule rule) {
        OnlineValuationRule update = new OnlineValuationRule();
        update.setId(rule.getId());
        update.setCanEditPrice(rule.getCanEditPrice());
        baseMapper.updateById(update);

        OnlineValuationRule onlineValuationRule = baseMapper.selectById(rule.getId());
        if (ObjectUtil.isNotNull(onlineValuationRule)) {
            //清除缓存
            primaryCachePutter.deleteOnlineValuation(onlineValuationRule.getDriverRegionId(), null);
        }
        return RestResult.success();
    }

    @Override
    public RestResult copyRule(Long ruleId, Long driverRegionId) {
        OnlineValuationRule onlineValuationRule = baseMapper.selectById(ruleId);
        OnlineValuationRule addOnlineValuationRule = BeanUtil.copyProperties(onlineValuationRule, OnlineValuationRule.class, "id");
        addOnlineValuationRule.setDriverRegionId(driverRegionId);
        addOnlineValuationRule.setIsActive(false);
        addOnlineValuationRule.setCanEditPrice(false);
        baseMapper.insert(addOnlineValuationRule);

        List<OnlineValuationRuleDetail> onlineValuationRuleDetails = onlineValuationRuleDetailMapper.selectList(Wrappers.<OnlineValuationRuleDetail>lambdaQuery()
                .eq(OnlineValuationRuleDetail::getRuleId, ruleId));
        for (OnlineValuationRuleDetail onlineValuationRuleDetail : onlineValuationRuleDetails) {
            OnlineValuationRuleDetail addOnlineValuationRuleDetail = BeanUtil.copyProperties(onlineValuationRuleDetail, OnlineValuationRuleDetail.class, "id", "ruleId");
            addOnlineValuationRuleDetail.setRuleId(addOnlineValuationRule.getId());
            onlineValuationRuleDetailMapper.insert(addOnlineValuationRuleDetail);
        }

        return RestResult.success();
    }


    private Dict setOption(String[] options) {
        Dict optionDict = new Dict();
        for (String option : options) {
            optionDict.put(option, true);
        }
        return optionDict;
    }


    @Override
    public RestResult mockPricing(OnlineValuationMockPricingWrapper mockPricing) {
        OnlineValuationRule onlineValuationRule = baseMapper.selectById(mockPricing.getId());
        if (ObjectUtil.isNull(onlineValuationRule)) {
            return RestResult.failed("操作失败,该规则不存在");
        }
        List<OnlineValuationRuleDetail> details = onlineValuationRuleDetailMapper.selectList(Wrappers.<OnlineValuationRuleDetail>lambdaQuery()
                .eq(OnlineValuationRuleDetail::getRuleId, onlineValuationRule.getId()));
        DateTime rideStartDate = mockPricing.getStartTime();
        DateTime rideEndDate = DateUtil.offsetMinute(rideStartDate, mockPricing.getMinute());
        //获得指定日期是星期几，1表示周日，2表示周一
        int i = DateUtil.dayOfWeek(rideStartDate);
        Boolean isWeekend = i == 1 || i == 7;
        List<OnlineValuationRuleDetail> filterDetails = details.stream()
                .filter(detail -> detail.getIsWeekend().equals(isWeekend))
                .collect(Collectors.toList());
        for (OnlineValuationRuleDetail detail : filterDetails) {
            List<DateUtils.TimeRange> timeRanges = JSON.parseArray(detail.getPeriod(), DateUtils.TimeRange.class);
            boolean inTimeRange = DateUtils.isInTimeRange(mockPricing.getStartTime().toString(), timeRanges);
            if (inTimeRange) {
                //起步公里
                BigDecimal startKmConfig = JSON.parseObject(onlineValuationRule.getStartingRule()).getBigDecimal("mileage");
                Integer freeWaitMinuteConfig = JSON.parseObject(onlineValuationRule.getStartingRule()).getInteger("time");
                OnlinePriceDto onlinePriceDto = JSON.parseObject(detail.getPriceRule(), OnlinePriceDto.class);
                //超出起步公里数费用
                BigDecimal excessKmAmount = BigDecimal.ZERO;
                //超出时长的费用
                BigDecimal excessMinuteAmount = BigDecimal.ZERO;
                //判断是否超过起步公里数
                if (mockPricing.getKm().compareTo(startKmConfig) > 0) {
                    BigDecimal excessKm = mockPricing.getKm().subtract(startKmConfig);
                    excessKmAmount = excessKm.multiply(Convert.toBigDecimal(onlinePriceDto.getExceedStarting().getMileageUnitPrice()));
                }
                //判断是否超过时长
                if (mockPricing.getMinute() > freeWaitMinuteConfig) {
                    Integer excessMinute = mockPricing.getMinute() - freeWaitMinuteConfig;
                    excessMinuteAmount = Convert.toBigDecimal(excessMinute).multiply(Convert.toBigDecimal(onlinePriceDto.getExceedStarting().getTimeUnitPrice()));
                }
                //计算返空费
                BigDecimal emptyBackFeeAmount = BigDecimal.ZERO;
                if (ObjectUtil.isNotNull(onlinePriceDto.getEmptyBackFee())) {
                    Integer baseMileage = Convert.toInt(onlinePriceDto.getEmptyBackFee().getBaseMileage());
                    if (mockPricing.getKm().compareTo(Convert.toBigDecimal(baseMileage)) > 0) {
                        //里程费
                        BigDecimal kmAmount = Convert.toBigDecimal(onlinePriceDto.getStartingPrice()).add(excessKmAmount);
                        emptyBackFeeAmount = kmAmount.multiply(Convert.toBigDecimal(onlinePriceDto.getEmptyBackFee().getRatio()));
                    }
                }
                //计算恶劣天气附加费
                BigDecimal badWeatherAmount = BigDecimal.ZERO;
                if (ObjectUtil.isNotNull(onlinePriceDto.getBadWeather())) {
                    Date startTime = DateUtil.parseDateTime(onlinePriceDto.getBadWeather().getStartTime());
                    Date endTime = DateUtil.parseDateTime(onlinePriceDto.getBadWeather().getEndTime());
                    if (DateUtil.isIn(rideStartDate, startTime, endTime)) {
                        badWeatherAmount = Convert.toBigDecimal(5);
                    }
                }


                //节假日附加费
                BigDecimal holidayAmount = BigDecimal.ZERO;
                if (ObjectUtil.isNotNull(onlinePriceDto.getHoliday())) {
                    Object[] days = onlinePriceDto.getHoliday().getDays();
                    for (Object day : days) {
                        DateUtils.TimeRange dayItem = JSON.parseObject(Convert.toStr(day), DateUtils.TimeRange.class);
                        if (DateUtil.isIn(rideStartDate, DateUtil.parseDateTime(dayItem.getStartTime()), DateUtil.parseDateTime(dayItem.getEndTime()))) {
                            holidayAmount = Convert.toBigDecimal(onlinePriceDto.getHoliday().getPrice());
                            break;
                        }
                    }
                }


                BigDecimal totalAmount = excessKmAmount//超出里程 费
                        .add(excessMinuteAmount)//超时时间费
                        .add(Convert.toBigDecimal(onlinePriceDto.getStartingPrice()))//起步价
                        .add(emptyBackFeeAmount)//返空费
                        .add(badWeatherAmount)//恶劣天气附加费
                        .add(holidayAmount)//节假日附加费
                        ;
                return RestResult.success(totalAmount);
            }
        }
        return RestResult.success();
    }
}